package editor.manager;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.JEditorPane;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

import org.apache.commons.io.FileUtils;

import editor.Context;
import editor.Mode;
import editor.mouse.ProjectMouseAdapter;
import editor.project.Project;
import editor.project.Project.ReturnCode;
import editor.project.ProjectTree;


/**
 * Manages the Projects
 * 
 * @author Mark Dessain
 */
@SuppressWarnings("serial")
public class ProjectManager extends JScrollPane implements Manager, TreeSelectionListener
{

	private DefaultMutableTreeNode top = new DefaultMutableTreeNode("Projects");	
	private ProjectTree tree = new ProjectTree(top);

	private Boolean displayFiles = true;
	
	/**
	 * Project Manager
	 * 
	 * @param addListener True if right click should be enabled, False if right click should be disabled
	 * @param displayFiles True if files should be displayed as well as folders, False otherwise
	 */
	public ProjectManager(Boolean addListener, Boolean displayFiles)
	{  
		this.displayFiles = displayFiles;
		
		if(addListener)
		{
			tree.addMouseListener(new ProjectMouseAdapter(tree));		
		}
		
		tree.addTreeSelectionListener(this);

		getViewport().add(tree);
	}

	
	/**
	 * Project Manager with right click and files enabled
	 */
	public ProjectManager()
	{  
		this(true, true);
	}
	

	/**
	 * @param project the project to copile
	 * @return True if no errors, False if errors
	 */
	public boolean compileProject(Project project)
	{
		Context.switchMode(Mode.CODING);
		Context.setMainProject(project);

		Boolean errorPresent = false;
		
		JEditorPane test = WorkSpaceManager.consoleManager.getJavaConsole();
		StringBuilder errorBuilder = new StringBuilder();
		test.setText("");
		
		try {
			
			project.compile();
			
			InputStream errorStream = project.getCompileErrorStream();
			InputStreamReader isr = new InputStreamReader(errorStream);
			BufferedReader br = new BufferedReader(isr);
			String line;

			// appends them together in one string
			while ((line = br.readLine()) != null) {

				errorPresent = true;

				// Error location line
				Pattern patt = Pattern.compile("([\\Wa-zA-Z0-9_]*):([0-9]*):");
				Matcher m = patt.matcher(line);

				// If a match is found
				while (m.find()) {
					String errorFile = m.group(1);
					String errorLine = m.group(2);

					// Create a link with the file and line number
					errorBuilder.append("<a href=\"" + errorFile + ":" + errorLine + "\">" + errorFile + ":" + errorLine + ":</a>");
					line = line.substring(m.end());
				}

				// Append the rest of the line
				errorBuilder.append(line);
				errorBuilder.append("\n");
			}
			
			if(!errorPresent)
			{
				errorBuilder.append("Project compiled successfully.");
				test.setText("<pre>" + errorBuilder.toString() + "</pre>");
				return true;
			}
			else
			{
				test.setText("<pre>" + errorBuilder.toString() + "</pre>");
				return false;
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return false;
	}


	/**
	 * @param name of a new project
	 * @param directory of a new project
	 * @return ReturnCode on if there were any errors in creating the project
	 */
	public ReturnCode createProject(String name, String directory)
	{
		// Project object
		Project project = new Project(name, directory);

		if(Context.getEditorSettings().checkProjectDuplicate(project))
		{
			return ReturnCode.PROJECTEXISTS;
		}
		else
		{
			// Create the necessary folders for a project
			ReturnCode setup = project.setup();

			if(setup == Project.ReturnCode.OK)
			{
				// Add to the settings XML
				Context.getEditorSettings().addProject(project);	

				// Refresh the project tree
				loadProject(project);	
				refresh();
			}
			return setup;
		}
	}

	/**
	 * Loads all the project from the settings into the ProjectManager
	 */
	public void loadProjects()
	{
		ArrayList<Project> projects = Context.getEditorSettings().getProjects();
		for(Project project: projects)
		{
			loadProject(project);
		}
		
		refresh();
	}

	/**
	 * @param project loads the project 
	 */
	public void loadProject(Project project)
	{
		// Check to make sure all the correct folders exist
		boolean validate = project.isDirectory();

		if(validate)
		{
			top.add(project.load(displayFiles));	
		}
		else
		{
			//TODO error project not valid
		}
	}
	
	/**
	 * @param project project to close
	 * @param delete True if it should be deleted, False if not
	 */
	public void closeProject(Project project, boolean delete)
	{
		// TODO check if the project deleted
		if(delete)
		{
			try {
				FileUtils.deleteDirectory(project);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		Context.getEditorSettings().removeProject(project);
		
		reload();
	}
	
	/**
	 * @param project
	 */
	public void runProject(Project project)
	{
		// TODO :( not enough time, will attempt to complete for poster session
	}

	/**
	 * Refreshes the tree and view
	 */
	public void refresh()
	{
		// TODO we now need to expand all the previously open nodes
		tree.setModel(new DefaultTreeModel(top));	
		
		for (int i = 0; i < tree.getRowCount(); i++) {
	         tree.expandRow(i);
		}
	}

	/**
	 * Reloads all the projects
	 */
	public void reload()
	{
		// Destroys the tree and builds it back up again
		top = new DefaultMutableTreeNode("Projects");	
		loadProjects();
	}

	/**
	 * @return selected tree path
	 */
	public TreePath getSelectedNode()
	{
		return tree.getSelectionPath();
	}

	/**
	 * @return the tree
	 */
	public JTree getProjectTree()
	{
		return tree;
	}
	

	/* (non-Javadoc)
	 * @see javax.swing.event.TreeSelectionListener#valueChanged(javax.swing.event.TreeSelectionEvent)
	 */
	@Override
	public void valueChanged(TreeSelectionEvent e) {
		
		if(e.getPath() != null)
		{
			Context.getSideBarManager().setEnableExecuteProject(true);
		}
		else
		{
			Context.getSideBarManager().setEnableExecuteProject(false);
		}
		
	}

	/* (non-Javadoc)
	 * @see editor.manager.Manager#switchMode(editor.Mode)
	 */
	@Override 
	public void switchMode(Mode mode)
	{
		if(mode == Mode.CODING)
		{
			codingMode();
		}
		else if(mode == Mode.QUESTION)
		{
			questionMode();	
		}
		else if(mode == Mode.TESTING)
		{
			testingMode();
		}
	}

	/* (non-Javadoc)
	 * @see editor.manager.Manager#codingMode()
	 */
	@Override
	public void codingMode(){}

	/* (non-Javadoc)
	 * @see editor.manager.Manager#questionMode()
	 */
	@Override
	public void questionMode(){}

	/* (non-Javadoc)
	 * @see editor.manager.Manager#testingMode()
	 */
	@Override
	public void testingMode(){}


}